﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class Transition : IEnumerable<string>
{
    #region Fields

    private State from;
    private State to;
    private HashSet<string> values;

    #endregion

    #region Constructors

    protected Transition(State parent, State to)
    {
        this.from = parent;
        this.to = to;
        this.values = new HashSet<string>();
    }

    public Transition(State parent, State to, string value)
        : this(parent, to)
    {
        AddValue(value);
    }

    public Transition(State parent, State to, params string[] values)
        : this(parent, to)
    {
        AddValues(values);
    }

    public Transition(State parent, State to, ICollection<string> values)
        : this(parent, to)
    {
        AddValues(values);
    }

    #endregion

    #region Properties

    public State From
    {
        get
        {
            return this.from;
        }
    }

    public State To
    {
        get
        {
            return this.to;
        }
    }

    public HashSet<string> ValuesSet
    {
        get
        {
            return this.values;
        }
    }

    public List<string> Values
    {
        get
        {
            return this.values.ToList();
        }
    }

    public int Count
    {
        get
        {
            return this.values.Count;
        }
    }

    #endregion

    #region Methods

    public void AddValue(string value)
    {
        values.Add(value);
    }

    public void AddValues(params string[] values)
    {
        foreach (string transitionValue in values)
        {
            this.values.Add(transitionValue);
        }
    }

    public void AddValues(ICollection<string> values)
    {
        foreach (string transitionValue in values)
        {
            this.values.Add(transitionValue);
        }
    }

    public bool Contains(string value)
    {
        return this.values.Contains(value);
    }

    public bool ContainsEpsilon()
    {
        return this.values.Contains(FiniteStateMachine.Epsilon);
    }

    public string ToFullString(string epsilonName)
    {
        StringBuilder output = new StringBuilder();
        output.Append(String.Format("{0} -> ", from));
        if (values.Count > 0)
        {
            foreach (string transitionValue in values)
            {
                if (transitionValue == FiniteStateMachine.Epsilon)
                {
                    output.AppendFormat("{0}, ", epsilonName);
                }
                else
                {
                    output.Append(String.Format("{0}, ", transitionValue));
                }
            }
            output.Remove(output.Length - 2, 2);
        }
        output.Append(String.Format(" -> {0}", to));

        return output.ToString();
    }

    public string ToFullString()
    {
        return ToFullString("Epsilon");
    }

    public override string ToString()
    {
        StringBuilder output = new StringBuilder();
        if (values.Count > 0)
        {
            foreach (string transitionValue in values)
            {
                output.Append(String.Format("{0}, ", transitionValue));
            }
            output.Remove(output.Length - 2, 2);
        }

        return output.ToString();
    }

    public IEnumerator<string> GetEnumerator()
    {
        foreach (string value in this.values)
        {
            yield return value;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}